import random
from tempfile import NamedTemporaryFile

import aiofiles
from django.http import FileResponse
from rest_framework.request import Request
from rest_framework.decorators import action
from rest_framework.generics import GenericAPIView
from rest_framework.parsers import BaseParser
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status, viewsets
from django_q.tasks import async_task

from misaka.permissions import isLogin, hasUser
from .models import FileMeta, FileModel, BlockFileModel
from .serializers import ListFileModelSerializer, BlockFileModelSerializer
from .tasks import save_file
from django.shortcuts import get_object_or_404


class FastUploadView(APIView):
    """
    快速上传
    通过对比md5值来判断是否可以快速上传
    RequestBody:
    {
        "md5": "文件本身的hash值",
        "block": "文件是第几个分片"
    }
    """

    def post(self, request: Request):
        data: dict = request.data

        md5 = data.get('md5')
        block = data.get('block', 0)

        try:
            # 如果存在相同的文件 那么直接快速上传
            file = FileModel.objects.filter(md5=md5)
            if file.count() < 1:
                raise FileModel.DoesNotExist()
            else:
                file: FileModel = file.first()

            new_file = FileModel.objects.create(
                file_mapper=file,
                md5=md5,
                block_order=block,
                filename=file.filename,
                file=file.file
            )
            serializer = ListFileModelSerializer(instance=new_file)
            print(serializer)
            return Response(serializer.data, status=200)  # 快速上传通过

        except FileModel.DoesNotExist:
            return Response(False, status=201)  # 无法进行快速上传


class DownloadFileView(APIView):
    """
    下载文件
    RequestBody:
    {
        file-id: "文件对应的id"
    }
    """

    async def post(self, request: Request):
        data = request.data
        file_id = data.get("file-id")

        # 获取文件实例
        file_instance = get_object_or_404(FileModel, id=file_id)

        # 异步打开文件
        try:
            async with aiofiles.open(file_instance.file.path, 'rb') as f:
                # 创建一个流响应来避免一次性读取全部文件到内存
                response = FileResponse(f, content_type='application/octet-stream')
                response['Content-Disposition'] = f'attachment; filename="{file_instance.file.name}"'
                return response
        except FileNotFoundError:
            return Response("文件未找到", status=404)
        except Exception as e:
            return Response(f"处理文件时发生错误: {str(e)}", status=500)


class FileUploadAPIView(APIView):
    """
    上传文件
    RequestBody:
    {
        file: "文件本身的内容",
        file_md5: "文件的计算hash值",
        block: "所在完整文件的第几个分区",
        [descript: "文件的描述"],

    }
    """
    authentication_classes = [isLogin]
    permission_classes = [hasUser]

    def patch(self, request: Request):
        data: dict = request.data
        print(data)
        uploaded_file = data.get('file')
        data['full_filename'] = uploaded_file.name

        # 使用 NamedTemporaryFile 创建临时文件
        with NamedTemporaryFile(delete=False) as temp_file:
            for chunk in uploaded_file.chunks():
                temp_file.write(chunk)
            # 保存临时文件的路径到 data
            data['temp_file_path'] = temp_file.name
            del data['file']  # 删除二进制文件 因为传不到DjangoQ里面去
        print('执行异步任务')
        file_id = async_task(save_file, request.user.id,data)

        return Response(
            {"message": "文件正在保存.", "async_id": file_id},
            status=200
        )


class BlockFileModelView(viewsets.ModelViewSet):
    queryset = BlockFileModel.objects.all()
    serializer_class = BlockFileModelSerializer
    search_fields = ['show_filename']
    ordering_fields = ['show_filename', 'create_time']

    @action(detail=True, methods=['post'], url_path='update-file-meta')
    def update_file_meta(self, request, pk=None):
        try:
            block_file_instance = self.get_object()
            file_meta = block_file_instance.file_meta
            if file_meta:
                # 获取请求中的新描述文本
                new_file_description = request.data.get('file_description', file_meta.file_description)
                # 更新 file_description
                file_meta.file_description = new_file_description
                file_meta.save()
                return Response({"message": "FileMeta updated successfully"}, status=status.HTTP_200_OK)
            else:
                return Response({"error": "FileMeta does not exist"}, status=status.HTTP_404_NOT_FOUND)
        except BlockFileModel.DoesNotExist:
            return Response({"error": "BlockFileModel not found"}, status=status.HTTP_404_NOT_FOUND)
